/********************************************************************
	created:	2010/08/27
	created:	27:8:2010   3:22
	filename: 	qyQuatTS.h
	author:		Xiong Jiayu
	purpose:	
*********************************************************************/
#pragma once

#ifndef __QYQUATTS_H__
#define __QYQUATTS_H__

#include "qyVector3.h"
#include "qyQuat.h"
#include "qyMatrix4.h"

/*
===========================================
struct QuatTS
===========================================
*/
struct QuatTS
{
public:
	Quat	q;
	Vector3	t;
	Vector3 s;

public:
						QuatTS();
						QuatTS( const Quat &q, const Vector3 &t, const Vector3 &s );
						QuatTS( const QuatTS &qts );

	void				Set( const Quat &q, const Vector3 &t, const Vector3 &s );
	void				Set( const Quat &q, const Vector3 &t );
	void				Set( const Quat &q );
	void				SetTranslate( const Vector3 &t );
	void				SetScale( const Vector3 &s );

	QuatTS				Inverse( void ) const;
	QuatTS &			InverseSelf( void );
	void				Identity( void );

	QuatTS & 			Slerp( const QuatTS &from, const QuatTS &to, float weight );
	QuatTS &			SlerpFast( const QuatTS &from, const QuatTS &to, float weight );

	void				ToMatrix4( Matrix4 &mat ) const;
	void				FromMatrix4( const Matrix4 &mat );

	QuatTS				operator*( const QuatTS &qts ) const;
	void				operator*=( const QuatTS &qts );
	QuatTS				operator*( const QuatT &qt ) const;
	void				operator*=( const QuatT &qts );
	QuatTS				operator*( const Quat &q ) const;
	void				operator*=( const Quat &q );

	QuatTS &			operator=( const QuatTS &a );
};

//-----------------------------------------------------------------------
const QuatTS quatTS_identity( 
				Quat( 0, 0, 0, 1 ), 
				Vector3( 0, 0, 0 ), 
				Vector3( 1, 1, 1 ) );

//-----------------------------------------------------------------------
QY_INLINE QuatTS::QuatTS()
{
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS::QuatTS( const Quat &_q, const Vector3 &_t, const Vector3 &_s )
: q( _q )
, t( _t )
, s( _s )
{
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS::QuatTS( const QuatTS &qts )
: q( qts.q )
, t( qts.t )
, s( qts.s )
{

}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::Set( const Quat &_q, const Vector3 &_t, const Vector3 &_s )
{
	q = _q; t = _t; s = _s;
}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::Set( const Quat &_q, const Vector3 &_t )
{
	q = _q; t = _t;
}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::Set( const Quat &_q )
{
	q = _q;
}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::SetTranslate( const Vector3 &_t )
{
	t = _t;
}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::SetScale( const Vector3 &_s )
{
	s = _s;
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS QuatTS::Inverse( void ) const
{
	return QuatTS( q.Inverse(), -t, Vector3( 1.0f / s.x, 1.0f / s.y, 1.0f / s.z ) );
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS & QuatTS::InverseSelf( void )
{
	q.InverseSelf();
	t = -t;
	s.x = 1.0f / s.x;
	s.y = 1.0f / s.y;
	s.z = 1.0f / s.z;
}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::Identity( void )
{
	q.Identity();
	t.Zero();
	s.Set( 1.0f, 1.0f, 1.0f );
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS &QuatTS::Slerp( const QuatTS &floatrom, const QuatTS &to, float weight )
{
	q.Slerp( floatrom.q, to.q, weight );
	t.x   = floatrom.t.x*(1-weight)   + to.t.x*weight;
	t.y   = floatrom.t.y*(1-weight)   + to.t.y*weight;
	t.z   = floatrom.t.z*(1-weight)   + to.t.z*weight;

	s     = floatrom.s*(1-weight)     + to.s*weight;
	return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS &QuatTS::SlerpFast( const QuatTS &from, const QuatTS &to, float weight )
{
	q.SlerpFast( from.q, to.q, weight );
	t.x   = from.t.x*(1-weight)   + to.t.x*weight;
	t.y   = from.t.y*(1-weight)   + to.t.y*weight;
	t.z   = from.t.z*(1-weight)   + to.t.z*weight;

	s     = from.s*(1-weight)     + to.s*weight;
	return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS QuatTS::operator *( const QuatTS &a ) const
{
	return QuatTS( q*a.q, (a.q*t).Scale(a.s) + a.t, a.s.Scale(s) );
}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::operator*=( const QuatTS &a )
{
	QuatTS temp = (*this) * a;
	*this = temp;
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS & QuatTS::operator =( const QuatTS &a )
{
	q = a.q;
	t = a.t;
	s = a.s;
	return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS QuatTS::operator *( const QuatT &a ) const
{
	return QuatTS( q*a.q, a.q * t + a.t, s );
}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::operator *=( const QuatT &a )
{
	QuatTS temp = (*this) * a;
	(*this) = temp;
}

//-----------------------------------------------------------------------
QY_INLINE QuatTS QuatTS::operator *( const Quat &a ) const
{
	return QuatTS( q*a, t, s );
}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::operator *=( const Quat &a )
{
	QuatTS temp = (*this ) * a;
	(*this) = temp;
}

//-----------------------------------------------------------------------
QY_INLINE void QuatTS::ToMatrix4( Matrix4 &m ) const
{
	m.Identity();
	float vxvx=q.x*q.x;				float vzvz=q.z*q.z;				float vyvy=q.y*q.y; 
	float vxvy=q.x*q.y;				float vxvz=q.x*q.z;				float vyvz=q.y*q.z; 
	float svx=q.w*q.x;				float svy=q.w*q.y;				float svz=q.w*q.z;
	m[0][0]=(1-(vyvy+vzvz)*2)*s.x;	m[1][0]=(vxvy-svz)*2*s.y;		m[2][0]=(vxvz+svy)*2*s.z;		m[3][0]=t.x;
	m[0][1]=(vxvy+svz)*2*s.x;		m[1][1]=(1-(vxvx+vzvz)*2)*s.y;	m[2][1]=(vyvz-svx)*2*s.z;		m[3][1]=t.y;
	m[0][2]=(vxvz-svy)*2*s.x;		m[1][2]=(vyvz+svx)*2*s.y;		m[2][2]=(1-(vxvx+vyvy)*2)*s.z;	m[3][2]=t.z;
}

#endif
 